import { TaskItem } from "@/modules/dev-env/task/task-item.ts";
import path from "@/framework/util/path.ts";
import type { GenericEnvStore } from "@/modules/dev-env/store/generic-env-store.ts";
import type { BaseEnvMirror } from "@/modules/dev-env/mirror/mirror.ts";
import { notification } from "ant-design-vue";
import type { ToolInstallVersionItem } from "@/modules/dev-env/common/types.ts";
import { noop } from "@/framework/util/warning.ts";
import { formatBytes } from "@/framework/util/bytes.ts";
import { EnvTree } from "@/modules/dev-env/common/tree.ts";

/**
 * 压缩包安装参数
 */
export interface ArchiveInstallOptions {
  /**
   * 安装完成后是否删除安装文件
   */
  deleteInstallerAfterInstall?: boolean;
}

/**
 * 软件压缩包安装任务
 */
export class ArchiveInstallTask extends TaskItem {
  /**
   * 安装选项
   */
  readonly opts: ArchiveInstallOptions;
  /**
   * 下载文件本地保存路径
   */
  readonly localFile: string;
  /**
   * 解压输出目录
   */
  readonly unzipOutputDir: string;

  readonly store: GenericEnvStore<any>;
  readonly mirror: BaseEnvMirror;
  readonly version: ToolInstallVersionItem;

  downloading = false;
  unzipping = false;
  totalBytes = 0;

  constructor(store: GenericEnvStore<any>, mirror: BaseEnvMirror, version: ToolInstallVersionItem, opts: ArchiveInstallOptions) {
    super(version.id, version.name);
    this.store = store;
    this.mirror = mirror;
    this.version = version;
    this.opts = opts;

    this.localFile = store.getDownloadPath(version.name);
    this.unzipOutputDir = version.extraToTempdir
      ? path.join(store.installDir, EnvTree.tempDir, version.installPath)
      : path.join(store.installDir, EnvTree.versionsDir, mirror.variant, version.installPath);

    this.status = {
      desc: "",
      detail: version.url,
    };
  }

  protected async run(): Promise<void> {
    this.speedDisplay = null;

    const exists = await native.fs.exists(this.localFile);
    if (!exists) {
      // 下载文件
      await this._downloadFile();
    } else {
      this.percent = 100;
    }
    if (__DEV__) console.log(`[archive-install-task] downloaded: ${this.localFile}`);
    // 解压并安装
    await this._unzipFile();

    if (__DEV__) console.log(`[archive-install-task] install complete: id=${this.id}, name=${this.name}`);
    this.emit("complete");

    // 刷新本地版本列表
    this.store.loadLocalVersions().catch(noop);
  }

  protected onRunError() {
    this.status = { desc: "安装失败", detail: this.error };
    notification.error({ message: `${this.name}安装失败`, description: this.error });
  }

  protected onRunFinally() {
    this.downloading = false;
    this.unzipping = false;
  }

  private async _downloadFile() {
    this.downloading = true;
    if (__DEV__) console.log(`[archive-install-task] downloading: ${this.version.url} => ${this.localFile}`);

    this.percent = 0;
    this.status = { desc: "正在下载", detail: this.version.url };
    await native.http.download({
      id: this.id,
      url: this.version.url,
      savePath: this.localFile,
      progress: e => {
        this.percent = Math.floor(e.percent * 100);
        this.speedDisplay = `${formatBytes(e.speed)}/s`;
        this.processedDisplay = formatBytes(e.transferred);
        if (e.total != this.totalBytes) {
          this.totalBytes = e.total;
          this.totalDisplay = formatBytes(e.total);
        }
      },
    });
    this.downloading = false;
  }

  private async _unzipFile() {
    this.unzipping = true;
    this.status = { desc: "正在解压", detail: this.localFile };
    if (__DEV__) console.log("[archive-install-task] unziping file:", this.localFile, ">", this.unzipOutputDir);
    const ret = await native.archives.unzip({
      id: this.id,
      archiveFile: this.localFile,
      outputDir: this.unzipOutputDir,
    });
    if (__DEV__) console.log("[archive-install-task] unzip success:", ret);
    this.unzipping = false;
    this.status = { desc: "解压完成", detail: this.unzipOutputDir };

    // 执行安装回调
    if (this.mirror.afterUnzipComplete) {
      await this.mirror.afterUnzipComplete(ret, this.version);
    }
    if (this.store.afterUnzipComplete) {
      await this.store.afterUnzipComplete(ret, this.version);
    }

    // 删除安装包
    if (this.opts.deleteInstallerAfterInstall) {
      if (__DEV__) console.log("[archive-install-task] delete archive file:", this.localFile);
      native.fs.rm(this.localFile, { force: true }).catch(noop);
    }
  }

  protected handleCancel() {
    if (this.downloading) {
      native.http.cancelDownload(this.id);
    }

    if (this.unzipping) {
      native.archives.cancelUnzip(this.id);
    }
  }
}
